﻿using System;
using System.Linq;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using Sustainalytics.ClientDW.Entities;

namespace Sustainalytics.ClientDW.DataAccessLayer
{
    public class ClientDWMasterRepository : IClientDWMasterRepository
    {
        private static IMongoDatabase _database;
        private const string DatabaseName = "ClientDWMaster";

        private ClientDWMasterRepository() {}

        public static IClientDWMasterRepository GetInstance(string connectionString)
        {
            if (string.IsNullOrWhiteSpace(connectionString))
                throw new ArgumentException("MongoDB connection string key is empty or missing.");

            var client = new MongoClient(connectionString);
            _database = client.GetDatabase(DatabaseName);

            return new ClientDWMasterRepository();
        }

        public void Cleanup()
        {
            _database.Client.DropDatabase(DatabaseName);
        }

        public SyncLog GetLastSync(bool checkOnlyAutomatedSessions)
        {
            var collection = _database.GetCollection<SyncLog>(typeof(SyncLog).Name);
            collection.DeleteMany(Builders<SyncLog>.Filter.Eq(x=> x.Status, LastSessionStatus.Unknown));
            var lastSync = collection
                .Find(sl => (!checkOnlyAutomatedSessions || sl.IsAutomatedSync) && sl.Status == LastSessionStatus.Finished && sl.TimeEnd != null)
                .SortByDescending(sl => sl.TimeEnd)
                .FirstOrDefault();
            return lastSync;
        }

        public SyncLog GetLastStartedSync()
        {
            var collection = _database.GetCollection<SyncLog>(typeof(SyncLog).Name);
            var lastSync = collection
                .Find(_ => true)
                .SortByDescending(sl => sl.TimeStart)
                .FirstOrDefault();
            return lastSync;
        }

        public SyncLog AddNewEntryInSyncLog(bool isAutomatedSync)
        {
            var syncLog = new SyncLog
            {
                Id = Guid.NewGuid(),
                TimeStart = DateTime.UtcNow,
                TimeEnd = null,
                Status = LastSessionStatus.Running,
                IsAutomatedSync = isAutomatedSync
            };

            var collection = _database.GetCollection<SyncLog>(typeof(SyncLog).Name);

            collection.DeleteMany(Builders<SyncLog>.Filter.Eq(x => x.Status, LastSessionStatus.Unknown));

            collection.InsertOne(syncLog);

            return syncLog;
        }

        public void UpdateSyncLog(SyncLog syncLog)
        {
            if (syncLog == null)
            {
                throw new ArgumentException("No synchronization data provided for saving!");
            }

            var collection = _database.GetCollection<SyncLog>(typeof(SyncLog).Name);

            collection.FindOneAndUpdate(Builders<SyncLog>.Filter.Eq(x => x.Id, syncLog.Id),
                Builders<SyncLog>.Update
                    .Set(syncLog.PropertyName(x => x.TimeEnd), DateTime.UtcNow)
                    .Set(syncLog.PropertyName(x => x.Status), syncLog.Status)
                    .Set(syncLog.PropertyName(x => x.TimeSync), syncLog.TimeSync)
                    .Set(syncLog.PropertyName(x => x.DatabaseGroup), syncLog.DatabaseGroup));
        }
    }
}
